// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2005-1-13

#include "stdafx.h"
#include "trans_tcpsocket.h"
#include "trans_tcp.h"
#include "msvr_server.h"
#include "msvr_room.h"
#include "msvr_user.h"
#include <common/svr_base/svr_showinfo.h>
#include <common/svr_base/svr_netmsg.h>
#include "score_war3battle.h"
#include <common/netmsg/gameiddef.h> 

namespace JoyServer
{

class CJoyTransTCPMsgCloseSocket: public CJoyUserSetMsg
{
protected:
	virtual void OnExecute();
public:
	CJoyTransTCPSocket* m_socket;
	int errcode;
	CJoyTransTCPMsgCloseSocket(CJoyTransTCPSocket* sock, int err)
	{
	    m_socket = sock;
		errcode = err;
	}
	virtual ~CJoyTransTCPMsgCloseSocket()
	{
	}
};

void CJoyTransTCPMsgCloseSocket::OnExecute()
{
	CJoyMainRoom* pRoom = (CJoyMainRoom*)GetUserSet();
	CJoyAutoCS gate(pRoom->m_userLock);
    CJoyTransTCP* transTCP = pRoom->m_transTCP;
	
	CJoyMainUser* pUser;
    if(!transTCP->m_sockets.Lookup(m_socket, pUser))
    {
        return;
    }
  
	if (pUser == NULL)
	{
		return;
	}
  

	if (pRoom->m_roomGameId == GID_War3x || pRoom->m_roomGameId == GID_War3)
	{
		JoyServer::ScoreWar3::CPlayer* pPlayer = JoyServer::ScoreWar3::CPlayer::FromUser(pUser);

	    if (pPlayer != NULL)
	    {
		    pPlayer->m_leavecode = errcode;
			if (errcode == 0)
			{
				pPlayer->ExitBattle(JoyServer::ScoreWar3::BR_Test);
			}
			else
			{
				pPlayer->ExitBattle(JoyServer::ScoreWar3::BR_Exit);
			}
		}
	}

	m_socket->Close();
    transTCP->m_sockets.RemoveKey(m_socket);
    delete m_socket;
    pUser->m_tcpSock = NULL;

}


class CJoyTransTCPMsg : public CJoyUserSetMsg
{
protected:
    virtual void OnExecute();
public:
    CJoyTransTCPSocket* m_socket;
    CJoyTransmitData* m_recvData;

    CJoyTransTCPMsg(CJoyTransTCPSocket* sock, CJoyTransmitData* data)
    {
        m_socket    = sock;
        m_recvData  = data;
        data->AddRef();
    }
    virtual ~CJoyTransTCPMsg()
    {
        if(m_recvData != NULL)
        {
            m_recvData->Release();
        }
    }
};

void CJoyTransTCPMsg::OnExecute()
{
    CJoyMainRoom* pRoom = (CJoyMainRoom*)GetUserSet();

    CJoyAutoCS gate(pRoom->m_userLock);

    CJoyTransTCP* transTCP = pRoom->m_transTCP;
    CJoyMainUser* pUser;
    if(!transTCP->m_sockets.Lookup(m_socket, pUser))
    {
        return;
    }

    BYTE* pBuf = (BYTE*)m_recvData->m_buf.GetBuffer();
    int   nLen = m_recvData->m_buf.GetSize();
    CJoyBuffer& partBuf = m_socket->m_partBuf;
    if(!partBuf.IsEmpty())
    {
        partBuf.Append(pBuf, nLen);
        pBuf = (BYTE*)partBuf.GetBuffer();
        nLen = partBuf.GetSize();
    }

    while(nLen > sizeof(int))
    {
        int packLen = *(int*)pBuf;
        if(packLen > JOY_USER_MSG_MAX || packLen < 0)
        {
            m_socket->OnError(UserError_SockBadData);
            return;
        }
        int packAllLen = packLen+sizeof(int);
        if(packAllLen > nLen)
        {
            break;
        }
        void* pack  = pBuf+sizeof(int);
        pBuf += packAllLen;
        nLen -= packAllLen;

        JoyMessage::MessageBase* msg = JoyMsgTool::ExtractMsg(pack, packLen);
        if(msg == NULL)
        {
            m_socket->OnError(UserError_SockBadData);
            return;
        }
        if(pUser != NULL)
        {
            pUser->NetMsg_Recv(msg);
            continue;
        }
        // try to login.
        JoyMessage::MC_MainLogin* pLogin = (JoyMessage::MC_MainLogin*)msg;
        if(pLogin->IsValid())
        {
            if(pRoom->m_userIds.Lookup(pLogin->m_userId, (CJoyUser*&)pUser))
            {
                if(pUser->m_tcpSock != NULL)
                {
                    transTCP->m_sockets.RemoveKey(pUser->m_tcpSock);
                    pUser->m_tcpSock->Close();
                    delete pUser->m_tcpSock;
                }
                pUser->m_tcpSock = m_socket;
                transTCP->m_sockets[m_socket] = pUser;
                continue;
            }
        }
        transTCP->m_sockets.RemoveKey(m_socket);
        m_socket->Close();
        delete m_socket;
        return;
    }

    if(nLen > 0)
    {
        if(partBuf.IsEmpty())
        {
            partBuf.Append(pBuf, nLen);
        }
        else
        {
            partBuf.Remove(pBuf);
            ASSERT(partBuf.GetSize() == nLen);
        }
    }
    else
    {
        partBuf.RemoveAll();
    }
}


CJoyTransTCPSocket::CJoyTransTCPSocket()
{
    m_acceptedTick = GetTickCount();
    m_room = NULL;
}

CJoyTransTCPSocket::~CJoyTransTCPSocket()
{
}

void CJoyTransTCPSocket::OnError(int err)
{
    CJoyTransTCPMsgCloseSocket* pMsg = new CJoyTransTCPMsgCloseSocket(this, err);
	m_room->QueueMsg(pMsg);
}

void CJoyTransTCPSocket::OnRecv(CJoyTransmitData* recvData, const sockaddr_in&)
{
    CJoyTransTCPMsg* pMsg = new CJoyTransTCPMsg(this, recvData);
    m_room->QueueMsg(pMsg);
}


} // namespace JoyServer